<?php
/**
 * Created by PhpStorm.
 * User: yf
 * Date: 2018/10/26
 * Time: 7:23 PM
 */

namespace App\Utility;

use App\Model\ActivityBetModel;
use App\Model\ActivityBtypeModel;
use App\Model\ActivityStypeModel;
use App\Model\CouponsTypeModel;
use EasySwoole\Pool\Manager;
use stdClass;
use Throwable;

class CommonTool
{
    /**
     * 获取毫秒13位时间戳,不带小数点
     */
    public static function getMillisecondString()
    {
        list($ms, $sec) = explode(' ', microtime());
        return sprintf('%.0f', (floatval($ms) + floatval($sec)) * 1000);
    }

    /**
     * 对毫秒级字符串转换
     * @param string $time
     * @return string|string[]
     */
    public static function getMillisecondFormat(string $time)
    {
        if (strstr($time, '.')) {
            list($ms, $sec) = explode(".", $time);
        } else {
            $sec = $time;
            $ms = '000';
        }
        $date = date("Y-m-d H:i:s.x", $sec);
        return str_replace("x", $ms, $date);
    }

    /**
     * 获取时间差，毫秒级
     */
    public static function getSubtraction()
    {
        $t1 = microtime(true);
        $t2 = microtime(true);
        return (($t2 - $t1) * 1000) . 'ms';
    }

    /**
     * microsecond 微秒
     * millisecond 毫秒
     * 返回时间戳的毫秒数部分
     */
    public static function getMillisecond()
    {
        list($ms, $sec) = explode(" ", microtime());
        return round($ms * 1000);
    }

    /**
     * 返回当前 Unix 时间戳和微秒数(用秒的小数表示)浮点数表示，常用来计算代码段执行时间
     */
    public static function getMillisecondFloat()
    {
        list($ms, $sec) = explode(" ", microtime());
        return round((floatval($ms) + floatval($sec)), 3);
    }

    /**
     * 获取大小分类的名字
     * @param int $id
     * @param int $type
     * @return mixed
     */
    public static function getTypeName(int $id, int $type = 1)
    {
        $infoArray = self::getAllTypeMap($type);
        return $infoArray[$id];
    }

    /**
     * 返回活动赛事大分类型映射
     * @param int $type
     * @return array|mixed
     */
    public static function getAllTypeMap(int $type = 1)
    {
        if ($type == 1) {
            return (new ActivityBtypeModel())->getTypeMap();
        } else {
            return (new ActivityStypeModel())->getTypeMap();
        }
    }

    /**
     * 返回活动赛事投注倍所有数据
     */
    public static function getAllConsumeMap()
    {
        return (new ActivityBetModel())->getTypeMap();
    }

    /**
     * Redis分布锁 -- 加锁
     * @param string $name
     * @param int $lockExpire
     * @return bool
     * @throws Throwable
     */
    public static function redisLock(string $name = '', int $lockExpire = 10)
    {
        if (!$name) {
            return false;
        }

        $redis = new stdClass();
        // 设置锁名称
        $lockName = 'lock:' . $name;
        $boolean = false;

        try {
            $redis = Manager::getInstance()->get('redis')->getObj();

            // 设置锁值为当前时间戳 + 有效期
            $lockValue = time() + $lockExpire;
            /**
             * 创建锁
             * 试图以$lockKey为key创建一个缓存,value值为当前时间戳 + 有效期
             * 由于setnx()函数只有在不存在当前key的缓存时才会创建成功
             * 所以，用此函数就可以判断当前执行的操作是否已经有其他进程在执行了
             *
             * @var [type]
             */
            $lock = $redis->setnx($lockName, $lockValue);
            /**
             * 满足两个条件中的一个即可进行操作
             * 1、上面一步创建锁成功;
             * 2、   1）判断锁的值（时间戳）是否小于当前时间    $redis->get()
             *      2）同时给锁设置新值成功    $redis->getset()
             */
            if ($lock || ($redis->getSet($lockName, $lockValue) < time())) {
                // 给锁设置生存时间
                $redis->expire($lockName, $lockExpire);
                $boolean = true;
            }
        } catch (Throwable $e) {
            $boolean = false;
        } finally{
            Manager::getInstance()->get('redis')->recycleObj($redis);
            return $boolean;
        }
    }

    /**
     * Redis分布锁 -- 解锁
     * @param string $name
     * @return bool
     * @throws Throwable
     */
    public static function redisUnlock(string $name = '')
    {
        if (!$name) {
            return false;
        }

        $redis = new stdClass();
        // 设置锁名称
        $lockName = 'lock:' . $name;
        $boolean = false;

        try {
            $redis = Manager::getInstance()->get('redis')->getObj();
            if ($redis->ttl($lockName)) {
                $redis->del($lockName);
            }
            $boolean = true;
        } catch (Throwable $e) {
            $boolean = false;
        } finally{
            Manager::getInstance()->get('redis')->recycleObj($redis);
            return $boolean;
        }
    }


    /**
     * select返回的数组进行整数映射转换
     *
     * @param $data
     * @param array $map 映射关系二维数组  array(
     *                                          '字段名1'=>array(映射关系数组),
     *                                          '字段名2'=>array(映射关系数组),
     *                                           ......
     *                                       )
     * @return array|boolean
     *
     *  array(
     *      array('id'=>1,'title'=>'标题','status'=>'1','status_text'=>'正常')
     *      ....
     *  )
     */
    public static function intToString (&$data, $map = ['status' => [1 => '正常', -1 => '删除', 0 => '禁用']])
    {
        if ($data === false || $data === null) {
            return $data;
        }
        $data = (array)$data;
        foreach ($data as $key => $row) {
            foreach ($map as $col => $pair) {
                if (isset($row[$col]) && isset($pair[$row[$col]])) {
                    $data[$key][$col . '_text'] = $pair[$row[$col]];
                }
            }
        }
        return $data;
    }

    /**
     * 返回活动赛事优惠券类型所有数据
     */
    public static function getCouponsTypeMap()
    {
        return (new CouponsTypeModel())->getTypeMap();
    }
}